﻿using System;

namespace Pyramid.Hardware.Operations
{
    public class HalfAdder
    {
        private ILine _lineA;
        private ILine _lineB;
        private OutputLine _sumLine;
        private OutputLine _carryLine;

        public HalfAdder(ILine lineA, ILine lineB)
        {
            if (lineA == null)
                throw new ArgumentNullException("lineA");

            if (lineB == null)
                throw new ArgumentNullException("lineB");

            _lineA = lineA;
            _lineA.SignalChange += new EventHandler<SignalChangeEventArgs>(_line_SignalChange);

            _lineB = lineB;
            _lineB.SignalChange += new EventHandler<SignalChangeEventArgs>(_line_SignalChange);

            _sumLine = new OutputLine(CalculateSum());
            _carryLine = new OutputLine(CalculateCarry());
        }

        void _line_SignalChange(object sender, SignalChangeEventArgs e)
        {
            _sumLine.SetOutput(CalculateSum());
            _carryLine.SetOutput(CalculateCarry());
        }

        private Trivalent CalculateSum()
        {
            if (_lineA.Signal == Trivalent.True)
                return Trivalent.CycleUp(_lineB.Signal);
            else if (_lineA.Signal == Trivalent.False)
                return Trivalent.CycleDown(_lineB.Signal);
            else
                return _lineB.Signal;
        }

        private Trivalent CalculateCarry()
        {
            if (_lineA.Signal == _lineB.Signal)
                return _lineA.Signal;
            else
                return Trivalent.Unknown;
        }

        public ILine Sum
        {
            get
            {
                return _sumLine;
            }
        }

        public ILine Carry
        {
            get
            {
                return _carryLine;
            }
        }
    }
}
